# -*- coding: utf-8 -*-
"""
    The following copyright and license notice apply only to:
        - those parts of this Turbogears 2 project which are not
          part of the stock quickstarted project
        - those parts which are not otherwise licensed otherwise

    Copyright (C) 2009 Ciaran Farrell <cfarrell1980@gmail.com>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

from tg import expose, flash, require, url, request, redirect,tmpl_context,validate,config
from pylons.i18n import ugettext as _, lazy_ugettext as l_
#from catwalk.tg2 import Catwalk
from repoze.what import predicates
from genshi import XML
from lifepyscle.lib.base import BaseController
from lifepyscle.model import DBSession, metadata
from lifepyscle.controllers.error import ErrorController
from lifepyscle import model
from lifepyscle.model import *
from lifepyscle.controllers.secure import SecureController
from lifepyscle.widgets.add_party  import parties_autocomplete_form
#from lifepyscle.widgets.dummy import dummy_jeditable
from lifepyscle.widgets.quick_autocomplete import parties_single_autocomplete_form,party_parent_form
from lifepyscle.widgets import custom_validators
from lifepyscle.widgets.collection import *
from webhelpers import paginate # needed for list views
from lifepyscle.widgets.rating import Rating
from common import risk2txt,risks
cat="party" # added to every returned dict
default_ipp = config.get('default_pagination_items_per_page')

def groups():
    return DBSession.query(Group.group_id,Group.group_name).all()

def parties():
    return DBSession.query(Party.party_id,Party.name).all()

class PartyController(BaseController):

    #@expose('lifepyscle.templates.list_party')
    #@require(predicates.in_group('cman', msg=l_('Only for contract managers')))
    @expose()
    def index(self,**kw):
        #tmpl_context.find_party_form = parties_single_autocomplete_form
        #return dict(page="List Party",value=kw,parties=parties(),cat=cat,groups=groups())
        redirect(url('/party/list'))

    @expose('lifepyscle.templates.list_party')
    #@require(predicates.in_group('cman', msg=l_('Only for contract managers')))
    def list(self,**kw):
        tmpl_context.rating = remote_risk_form
        ipp=default_ipp # saved in app_cfg
        page=1 # a default which is changed by GET params
        if kw.has_key('ipp'): # see if the user set items_per_page himself
            if kw['ipp'].isdigit():
                ipp=int(kw['ipp'])
        if kw.has_key('page'): # see if the user set items_per_page himself
            if kw['page'].isdigit():
                page=int(kw['page'])
        parties = DBSession.query(Party).all()
        total = len(parties)
        tmpl_context.page = paginate.Page(parties,page=page,items_per_page=ipp,item_count=total)
        tmpl_context.gah = tmpl_context.page.pager('$link_previous ~3~ $link_next (Page $page of $page_count)',ipp=ipp)
        return dict(value=kw,cat=cat)

    @expose('lifepyscle.templates.add_party')
    #@require(predicates.in_group('cman', msg=l_('Only for contract managers')))
    def add(self,**kw):
        tmpl_context.rating = Rating(action="null")
        tmpl_context.add_parties_form = parties_autocomplete_form
        return dict(page="Add Party",value=kw,groups=groups(),parties=parties(),cat=cat)

    @expose()
    #@require(predicates.in_group('cman', msg=l_('Only for contract managers')))
    #@validate(form=parties_autocomplete_form,error_handler=add)
    def do_add(self,**kw):
        print kw
        """{'party_nick': u'jbob', 'parent_autocomplete': u'a', 'party_name': u'Jim Bob', 'star': u'2'}"""
        try:
            P = Party()
            P.name = kw['party_name']
            if kw.has_key('parent_autocomplete'):
                print kw['parent_autocomplete']
                try:
                    parent = DBSession.query(Party).filter(Party.name=='%s'%kw['parent_autocomplete']).one()
                except:
                    flash("No party was found with name '%s'. Ignored this parent party"%kw['parent_autocomplete'],'warning')
                else:
                    P.parent = parent
            if kw.has_key('party_nick'):
                P.nick = '%s'%kw['party_nick']
            if kw.has_key('star'):
                if kw['star'].isdigit():
                    risk = int(kw['star'])
                    R = Risk(risk)
                    P.risks.append(R)
                else:
                    flash("Invalid type received for risk","warn")
            DBSession.add(P)
        except Exception,e:
            flash(str(e),"error")
        else:
            flash("%s successfully added"%P.name,"info")
        redirect(url('/party/add'))

    @expose('lifepyscle.templates.test_autoc')
    def test(self,**kw):
        from lifepyscle.widgets.jqueryrating import JQueryRating
        tmpl_context.jqr = JQueryRating()
        return dict(cat=cat)

    @expose('json')
    def do_remote_add(self,**kw):
        if not kw.has_key('party_name'):
            return dict(error_msg="party_not_provided",party_name="",party_id="")
        else:
            if len(kw['party_name']) == 0:
                return dict(error_msg="party_empty",party_name="",party_id="")
            else:
                try:
                    existing = DBSession.query(Party.name).filter(Party.name=="%s"%kw['party_name']).one()
                except: # good - doesn't seem to exist
                    P = Party()
                    P.name = kw['party_name']
                    DBSession.add(P)
                    return dict(error_msg="",party_name=P.name,party_id=P.party_id)
                else: # not so good - party already exists
                    return dict(error_msg="party_exists",party_name="",party_id="")
                    


    @expose('json')
    def fetch_parties(self):
        p = []
        for x in parties():
            p.append(x.name)
        return dict(data=p)

    @expose()
    def by_id(self,**kw):
        """ Redirect to /party/view/id """
        if not kw.has_key('parties_autocomplete'):
            flash("You have to enter a party")
            u = "/party/list"
        else:
            print kw['parties_autocomplete']
            u = "/party/view/%s"%kw['parties_autocomplete']
        redirect(url(u))

    @expose()
    def by_name(self,**kw):
        """ Redirect to /party/view/id after retrieving the id"""
        if not kw.has_key('parties_autocomplete'):
            flash("You have to enter a party")
            u = "/party/list"
        else:
            print kw['parties_autocomplete']
            u = "/party/view/%s"%kw['parties_autocomplete']
        redirect(url(u))

    @expose('lifepyscle.templates.view_party')
    def view(self,id,**kw):
        from lifepyscle.widgets.rating import Rating
        from lifepyscle.widgets.edit_party import edit_party_form
        tmpl_context.rating = Rating()
        tmpl_context.edit_party_form = edit_party_form
        tmpl_context.remote_risk_form = remote_risk_form
        tmpl_context.parties_autocomplete = party_parent_form

        id = int(id)
        options = []
        try:
            P = DBSession.query(Party).filter(Party.party_id==id).one()
        except Exception,e:
            print e
            flash("No such party found",'warning')
            redirect(url('/party/list/'))
        else:
            if not P.parent:
                parent_name = ""
            else:
                parent_name = P.parent.name
            if P.avgRisk == 0:
                selected_risk = None
            else:
                selected_risk = P.avgRisk
            for x in risks.keys()[1:]:
                if selected_risk:
                    if x == selected_risk:
                        options.append(('%s'%str(x),"",{'class':'star','checked':'checked','name':'star'}))
                    else:
                        options.append(('%s'%str(x),"",{'class':'star','name':'star'}))
                else:
                    options.append(('%s'%str(x),"",{'class':'star','name':'star'}))
            if len(options)==0:
                for x in risks.keys()[1:]:
                    options.append(('%s'%str(x),"",{'class':'star','name':'star'}))
            return dict(cat=cat,page="View Party",party=P,parent_name=parent_name,risk_options=options)

    @expose('json')
    def update(self,id,value,**kw):
        print id,value
        # over the id param we get something like name_5 whereby what comes before the
        # underscore is the dbfield and what comes after is the party id
        f_p = id.split("_")
        try:
            field,party_id = f_p[0],f_p[1]
        except:
            print f_p
            return "busted"
        else:
            try:
                P = DBSession.query(Party).filter(Party.party_id==party_id).one()
            except:
                return "party doesn't exist, ya fool"
            else:
                if field.lower() == 'name':
                    P.name = value
                    return value
                elif field.lower() == 'nickname':
                    P.nick = value
                    return value
                elif field.lower() == 'description':
                    #P.description = value
                    #return value
                    pass
                else:
                    return "dont know that field"

    @expose('lifepyscle.templates.add_party')
    def clone(self,party_id,**kw):
        """ Get the info for kw['party_id'] and reuse /party/add """
        if not party_id.isdigit():
            msg = u'Invalid parameter party_id. This should be a digit'
        else:
            party_id = int(party_id)
            try:
                P = DBSession.query(Party).filter(Party.party_id == party_id).one()
            except:
                msg = u'No party found with id %d'%party_id
            else:
                print P.parent
                # handle the party_name
                unique_suggestion = False
                iter = 1
                while not unique_suggestion:
                    transient_suggestion = "%s_%d"%(P.name,iter)
                    try:
                        S = DBSession.query(Party.name).filter(Party.party_name.startswith(transient_suggestion)).one()
                    except:
                        name_suggest = transient_suggestion
                        unique_suggestion=True
                    else:
                        iter += 1
                # handle the party_nick
                unique_suggestion = False
                iter = 1
                while not unique_suggestion:
                    transient_suggestion = "%s_%d"%(P.nick,iter)
                    try:
                        S = DBSession.query(Party.nick).filter(Party.party_nick.startswith(transient_suggestion)).one()
                    except:
                        nick_suggest = transient_suggestion
                        unique_suggestion=True
                    else:
                        iter += 1
                if P.parent:
                    parent_suggest = P.parent.name
                else:
                    parent_suggest = ""
        tmpl_context.rating = Rating(action="null")
        tmpl_context.add_parties_form = parties_autocomplete_form
        value = kw
        value['parent_autocomplete'] = parent_suggest
        value['party_name'] = name_suggest
        value['party_nick'] = nick_suggest
        return dict(page="Clone Party",value=value,groups=groups(),parties=parties(),cat=cat)
                            
                    
    @expose()
    def do_party_update(self,**kw):
        atomic_ok = True
        party_id = None
        print kw
        if not kw.has_key('party_id'):
            atomic_ok = False
            msg = "Invalid parameter - missing key party_id"
        else:
            if not kw['party_id'].isdigit():
                atomic_ok = False
                msg = "Invalid parameter - party_id should be numeric"
            else:
                party_id = int(kw['party_id'])
        if party_id:
            try:
                P = DBSession.query(Party).filter(Party.party_id==party_id).one()
            except:
                atomic_ok = False
                msg = "Party with id %d not found"%party_id
            else:
                # First check the incoming party_name. As we are in edit modus, either the party_name
                # stays the same or it is changed. If it is changed, check that we don't overwrite
                # another party name which also exists
                if str(kw['party_name']) == str(P.name):
                    pass # this is what usually happens
                elif kw['party_name'] == "":
                    atomic_ok=False
                    msg = "You cannot delete the party name"
                else:
                    try:
                        existing = DBSession.query(Party.name).filter(Party.name == kw['party_name']).one()
                    except: # good, the other name does not exist - we can simply change the name later
                        pass
                    else: # bad - do not proceed here as a party with the new name already exists
                        atomic_ok = False
                        link = "<a href='#'>bah</a>"
                        msg = 'You cannot change the party name to %s as that party already exists!'%(kw['party_name'])
                # Same with the nick
                if str(kw['party_nick']) == str(P.nick):
                    pass # this is what usually happens
                else:
                    if kw['party_nick'] != "":
                        try:
                            existing = DBSession.query(Party).filter(Party.nick == kw['party_nick']).one()
                        except: # good, the other name does not exist - we can simply change the name later
                            pass
                        else: # bad - do not proceed here as a party with the new name already exists
                            atomic_ok = False
                            msg = 'You cannot change the party nickname to %s as that \
party nickname already exists for another party (%s)!'%(kw['party_nick'],existing.name)
                    else: # no problem with setting nick to an empty string
                        pass
                # Now deal with the parent party. Currently just check that a party is not a parent of itself
                if kw['parent_autocomplete'] == "": # no problem with having an empty parent
                    parent = None
                else:
                    if str(kw['parent_autocomplete']).lower() == str(P.name).lower():
                        atomic_ok = False
                        msg = 'You cannot set a party to be a parent of itself!'
                    else:
                        try:
                            parent = DBSession.query(Party).filter(Party.name=="%s"%kw['parent_autocomplete']).one()
                        except: # parent party doesn't exist?
                            atomic_ok = False
                            msg = "No party named %s exists. Try adding the party first"%kw['parent_autocomplete']
                        else:
                            pass
                # Now deal with the risk
                if not kw.has_key('star'):
                    pass
                else:
                    if not kw['star'].isdigit():
                        atomic_ok=False
                        msg="Risk must be a digit"
                    else:
                        if int(kw['star']) < 1 or int(kw['star']) > 5:
                            atomic_ok=False
                            msg="Risk must be between 1 and 5"
                        else:
                            pass
    
        else: # no party_id
            flash("Could not determine the party_id",'error')
            redirect(url('/party/list'))
        if not atomic_ok: # we only actually touch the database if all data is good
            flash(msg,'error')
        else:
            try:
                P.name = kw['party_name']
                P.nick = kw['party_nick']
                P.parent = parent
                try:
                    R = Risk(int(kw['star']))
                except Exception,e:
                    print "baH"
                    print e
                else:
                    P.risks.append(R)
            except Exception,e:
                flash("Oops: %s"%str(e),"error")
            else:
                flash("Successfully updated","ok")
        redirect(url('/party/view/%s'%str(party_id))) # party_id might not exist!
                        
